package com.lml;

import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.geometry.HPos;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import javafx.stage.FileChooser;
import javafx.stage.Stage;
import org.apache.commons.io.FileUtils;

import java.io.*;
import java.util.List;

/**
 * 行转列工具
 *
 * @author limenglong
 * @Description: 工作中，经常需要根据主键id走工单批量处理数据
 * sql的in语法需要将这些数据用逗号拼接，手动拼接巨费劲
 * 于是搞了这个小工具，每1000条数据单独生成一个文本
 * @date 2020/9/12 20:44
 */
public class TurnLine extends Application {

    /**
     * “打开文件位置”缓存
     */
    private static File cacheFile = new File("TurnLineCache.txt");

    /**
     * 程序入口
     *
     * @param args
     */
    public static void main(String[] args) {
        launch(args);
    }

    /**
     * 界面元素设置
     *
     * @param stage
     */
    @Override
    public void start(Stage stage) {
        stage.setTitle("行转列");
        final FileChooser fileChooser = new FileChooser();
        final Button openButton = new Button("选择文件");
        final Label label = new Label("775356536@qq.com");
        final ProgressBar progressBar = new ProgressBar();
        openButton.setOnAction(
                (final ActionEvent e) -> {
                    configureFileChooser(fileChooser);
                    File file = fileChooser.showOpenDialog(stage);
                    if (file != null) {
                        openFile(progressBar, file);
                    }
                });
        //网格布局
        GridPane gridPane = new GridPane();
        //横向元素间距
        gridPane.setHgap(12);
        //纵向元素间距
        gridPane.setVgap(12);
        gridPane.setPadding(new Insets(25, 25, 25, 25));
        gridPane.add(openButton, 0, 0);
        gridPane.add(progressBar, 1, 0);
        gridPane.add(label, 1, 1);
        gridPane.setHalignment(label, HPos.RIGHT);
        progressBar.setPrefWidth(350);
        Tooltip.install(gridPane, new Tooltip("选择txt文件，多行数据转为逗号连接，每1000行存为一个txt文件。"));
        final Pane rootGroup = new VBox(12);
        rootGroup.getChildren().addAll(gridPane);
        stage.setScene(new Scene(rootGroup, 500, 100));
        stage.setResizable(false);
        stage.show();
    }

    /**
     * 打开文件设置
     *
     * @param fileChooser
     */
    private static void configureFileChooser(final FileChooser fileChooser) {
        fileChooser.setTitle("选择文件");
        File directory = getCacheFile();
        if (null != directory) {
            fileChooser.setInitialDirectory(directory);
        }
        fileChooser.getExtensionFilters().addAll(
                new FileChooser.ExtensionFilter("txt", "*.txt")
        );
    }

    /**
     * 打开文件后执行的内容
     *
     * @param progressBar
     * @param file
     */
    private void openFile(ProgressBar progressBar, File file) {
        turn(progressBar, file);
        setCacheFile(file);
    }

    /**
     * 行转列，并同步进度条，监听并弹窗
     *
     * @param progressBar
     * @param f
     */
    private void turn(ProgressBar progressBar, File f) {
        Task worker = createWorker(f);
        progressBar.progressProperty().unbind();
        progressBar.progressProperty().bind(worker.progressProperty());
        worker.messageProperty().addListener(new ChangeListener<String>() {
            @Override
            public void changed(ObservableValue<? extends String> observable,
                                String oldValue, String newValue) {
                Alert alert = new Alert(Alert.AlertType.INFORMATION, newValue);
                alert.setHeaderText(null);
                alert.setTitle("提示");
                alert.show();
            }
        });
        new Thread(worker).start();
    }

    /**
     * 进度条任务，即：行转列
     *
     * @param f
     * @return
     */
    private Task createWorker(File f) {
        return new Task() {
            @Override
            protected Object call() throws Exception {
                String path = f.getParent();
                String fileName = f.getName().replace(".txt", "");
                List<String> lines = FileUtils.readLines(f, "UTF-8");
                StringBuffer buffer = new StringBuffer();
                int i = 0;
                updateProgress(0, lines.size());
                for (String line : lines) {
                    i++;
                    if (line.length() != 0) {
                        buffer.append("'" + line + "',");
                    }
                    if (i % 1000 == 0) {
                        buffer.deleteCharAt(buffer.length() - 1);
                        FileUtils.writeStringToFile(new File(path + "\\" + fileName + i / 1000 + ".txt"), String.valueOf(buffer), "UTF-8", false);
                        buffer.setLength(0);
                    }
                    updateProgress(i, lines.size());
                }
                //此方法执行后，会被监听到并执行changed里面的方法
                updateMessage("完成");
                buffer.deleteCharAt(buffer.length() - 1);
                FileUtils.writeStringToFile(new File(path + "\\" + fileName + (i / 1000 + 1) + ".txt"), String.valueOf(buffer), "UTF-8", false);
                return true;
            }
        };
    }

    /**
     * 获取路径缓存文件
     *
     * @return
     */
    private static File getCacheFile() {
        try {
            if (cacheFile.exists()) {
                InputStream inputStream = new FileInputStream(cacheFile);
                byte[] bytes = new byte[(int) cacheFile.length()];
                inputStream.read(bytes);
                return new File(new String(bytes));
            } else {
                return null;
            }
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 设置路径缓存文件
     *
     * @param file
     */
    private void setCacheFile(File file) {
        try {
            OutputStream outputStream = new FileOutputStream(cacheFile);
            byte[] bytes = file.getParent().getBytes();
            outputStream.write(bytes);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
